"""

    这是定义 PocketCubeCorner 的解法。

"""


class PocketCubeCorner:

    def __init__(self, coord: list[int], color: list[int] = None):
        if not color:
            color = [None, None, None]

        self.coord = coord
        self.color = color

    @staticmethod  # 优化后的向量旋转方法
    def rotate_vector_around_axis_optimized(v: list, axis: int, clockwise=True):
        x, y, z = v

        # 将旋转影响的分量提取出来，看作二维平面上的旋转
        def mix(x, y, clockwise: bool):
            flag = x * y * (1 if clockwise else -1)
            if flag == 1:
                return x, -y
            else:
                return -x, y

        if axis == 0:  # x
            z, y = mix(z, y, clockwise)
        elif axis == 1:  # y
            x, z = mix(x, z, clockwise)
        elif axis == 2:
            y, x = mix(y, x, clockwise)
        else:
            raise ValueError(f"axis参数错误 - {axis}")

        return [x, y, z]

    def rotate(self, axis: int, clockwise: bool) -> None:
        """
        axis:
        0 - x
        1 - y
        2 - z
        """

        # print(self.coord, self.color, end=" → ")

        # set state of self.color
        color_exchange_index = [
            i for i in range(3) if i != axis
        ]

        t_color = self.color[color_exchange_index[0]]
        self.color[color_exchange_index[0]] = self.color[color_exchange_index[1]]
        self.color[color_exchange_index[1]] = t_color

        # set state of coord
        transition_index = (axis + 1) * (-1 if not clockwise else 1)

        self.coord = self.rotate_vector_around_axis_optimized(
            self.coord, axis, clockwise
        )

        # print(self.coord, self.color)


class PocketCube:
    corners: list[PocketCubeCorner]

    def __init__(self):

        # initialize self.corners
        self.corners: list[PocketCubeCorner] = []
        for x in (1, -1):
            for y in (1, -1):
                for z in (1, -1):
                    self.corners.append(
                        PocketCubeCorner(coord=[x, y, z])
                    )

        # initialize colors of corners
        """
        Front  F  R  0  1
        Back   B  O  1  1
        Up     U  W  2  2
        Down   D  Y  3  2
        Left   L  G  4  0
        Right  R  B  5  0
        """
        colors = [0, 1, 2, 3, 4, 5] # list("ROWYGB")
        color_indexes = [1, 1, 2, 2, 0, 0]
        for direction, color in enumerate(colors):
            corners_toColor = self.getCorners(direction)

            for corner in corners_toColor:
                corner.color[color_indexes[direction]] = color

    def getCorners(self, direction: int) -> list[PocketCubeCorner]:
        """
        0  F  y+
        1  B  y-
        2  U  Z+
        3  D  Z-
        4  L  x-
        5  R  x+
        """

        statements = [
            (1, 1),
            (1, -1),
            (2, 1),
            (2, -1),
            (0, -1),
            (0, 1),
        ]

        statement = statements[direction]

        rt = []
        for corner in self.corners:
            if corner.coord[statement[0]] == statement[1]:
                rt.append(corner)

        return rt

    def getCornerByCoord(self, coord: list[int]):
        for corner in self.corners:
            if corner.coord == coord:
                return corner

    def rotate(self, direction: int, clockwise: bool = True, times: int = 1) -> None:
        """
        direction：表示一种旋转方式 需要采用以下的0-5进行标号
        clockwise：顺时针时 为 True；逆时针时 为 False
        times：即旋转次数

        名称      公式符号   direction参数   axis参数  旋转轴校准
        Front    F         0              1         True
        Back     B         1              1         False
        Up       U         2              2         True
        Down     D         3              2         False
        Left     L         4              0         False
        Right    R         5              0         True
        """

        # if type(direction) != int:
        #     direction = direction[0]
        # print(direction)

        axises = [1, 1, 2, 2, 0, 0]
        direction_reverse = [True, False, True, False, False, True]

        corners = self.getCorners(direction)

        for _ in range(times):
            for corner in corners:
                corner.rotate(
                    axis=axises[direction],
                    clockwise=clockwise if direction_reverse[direction] else not clockwise
                )

    def show_front_up_right_view(self) -> str:
        """
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ ▇ ▇ A ▇ ▇ ▇               W                     W
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ B ▇ ▇ ▇ C ▇           W       W             W  上面  W
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         D ▇ ▇ E ▇ ▇ F         R     W     B         R     W     B
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ ▇ G ▇ H ▇ ▇             R   B             正面 R   B 右面
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         I ▇ ▇ ▇ ▇ ▇ J         R           B         R           B
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ ▇ K ▇ L ▇ ▇             R   B                 R   B
        """

        coords = [
            [-1, -1, 1],  # A
            [-1, 1, 1],  # B
            [1, -1, 1],  # C
            [-1, 1, 1],  # D
            [1, 1, 1],  # E
            [1, -1, 1],  # F
            [1, 1, 1],  # G
            [1, 1, 1],  # H
            [-1, 1, -1],  # I
            [1, -1, -1],  # J
            [1, 1, -1],  # K
            [1, 1, -1],  # L
        ]

        colorFace_indexes = [2, 2, 2, 1, 2, 0, 1, 0, 1, 0, 1, 0]

        color_list = [
            self.getCornerByCoord(coord).color[index] for coord, index in zip(coords, colorFace_indexes)
        ]

        # 为了方便，模板字符串已经给你准备好了
        template = \
            "      {}      \n  {}       {}  \n{}     {}     {}\n    {}   {}    \n{}           {}\n    {}   {}    \n"

        colorStrList = list("ROWYGB")

        # 模板字符串用 .format 方法进行填充
        return template.format(
            *[colorStrList[i] for i in color_list]
        )

    def act_formula(self, formula: str) -> None:
        """
        这个函数已经写好， 不需要你实现。
        这个函数接收一段魔方公式，解析成旋转方式并执行。
        """

        actions = list("FBUDLR")

        cursor = 0
        prev_config = [None, True, 1]

        try:
            while cursor < len(formula):
                char = formula[cursor]

                if char == "'":
                    prev_config[1] = not prev_config[1]

                if char.isdigit():
                    prev_config[2] = int(char)

                if char in actions:
                    if prev_config[0] is not None:
                        self.rotate(*prev_config)

                    prev_config = [actions.index(char), True, 1]

                if cursor == len(formula) - 1:
                    self.rotate(*prev_config)

                cursor += 1
        except:
            raise Exception("公式错误")


class CaseTester:
    """
    这是测试类，在主程序调用 CaseTester.test(放入你完成的二阶魔方类) 即可测试。

    请注意，您的魔方颜色的初始化一定要和测试案例相同，遵循以下规则：

    Front   正面    (R)Red
    Back    背面    (O)Orange
    Up      上面    (W)White
    Down    下面    (Y)Yellow
    Left    左面    (G)Green
    Right   右面    (B)Blue

    """

    TestCases = {
        "case1": {
            "input": "UR'2U'L2",
            "output": "      Y      \n  Y       Y  \nO     W     O\n    R   B    \nB           O\n    G   O    \n"
        },
        "case2": {
            "input": "D2LB'FL'R",
            "output": "      W      \n  O       W  \nG     R     O\n    B   W    \nG           R\n    B   W    \n"
        },
        "case3": {
            "input": "FB2U'F2DU",
            "output": "      B      \n  B       Y  \nY     G     G\n    R   W    \nB           B\n    R   Y    \n"
        },
        "case4": {
            "input": "FB2D'RFD'ULR",
            "output": "      B      \n  B       W  \nR     G     G\n    O   Y    \nY           O\n    B   Y    \n"
        },
        "case5": {
            "input": "D'L'R2FB'U'DF2U'",
            "output": "      R      \n  G       B  \nW     B     W\n    O   W    \nG           G\n    O   W    \n"
        },
        "case6": {
            "input": "D'R2FUF'D'L2FUD",
            "output": "      B      \n  W       W  \nR     W     B\n    O   G    \nY           G\n    W   B    \n"
        },
    }

    @classmethod
    def test(cls, PocketCube: type):

        if not type(PocketCube) == type:
            raise TypeError("类型错误，请放入PocketCube类。")

        import time

        TimeUses = []
        correct_times = 0
        for caseName, body in cls.TestCases.items():

            print(f"测试用例 - {caseName}  -----------------------")

            start_time = time.perf_counter()

            pocketCube = PocketCube()
            pocketCube.act_formula(body['input'])
            yourAns = pocketCube.show_front_up_right_view()

            end_time = time.perf_counter()

            print(f"你的答案\n\n{yourAns}\n")

            if yourAns == body['output']:
                print("正确！！！！")
                correct_times += 1
            else:
                print("错误！！！！")
                print(f"正确答案\n\n{body['output']}\n")

            elapsed_time = end_time - start_time
            TimeUses.append(elapsed_time)

            print(f"用时：{elapsed_time:.6f} 秒\n")

        print(f"{'-' * 80}\n平均用时：{sum(TimeUses) / len(TimeUses):.6f} 秒")
        print(f"正确率：{correct_times / len(cls.TestCases) * 100} %")


if __name__ == '__main__':

    CaseTester.test(PocketCube)

    # import time
    #
    # start_time = time.perf_counter()
    # pocketCube = PocketCube()
    # pocketCube.act_formula("UR'2U'L2D2LB'FL'RFB2U'F2DUFB2D'RFD'ULRD'L'R2FB'U'DF2U'D'R2FUF'D'L2FUD")
    # ans = pocketCube.show_front_up_right_view()
    # end_time = time.perf_counter()
    # elapsed_time = end_time - start_time
    #
    # print(ans)
    # print(f"用时 {elapsed_time:.6f} 秒")
